﻿using System.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;

namespace FeiYang
{
    class UI_
    {
        public static 回城_ 回城 = new 回城_();
        public static 去声望老人_ 去声望老人 = new 去声望老人_();
        public static 去马倌_ 去马倌 = new 去马倌_();
        public static 去炼狱旋涡_ 去炼狱旋涡 = new 去炼狱旋涡_();
        public static 去拉镖活动_ 去拉镖活动 = new 去拉镖活动_();
        public static 去王城任务_ 去王城任务 = new 去王城任务_();

        public static 去挖矿_ 去挖矿 = new 去挖矿_();
        public static string 识别左姓名()
        {
            return 图像_.识别文字(83, 674, 226, 696).Trim();
        }
        public static string 识别左职业()
        {
            return 图像_.识别文字(286, 674, 342, 696).Trim();
        }

        public static int 识别左等级()
        {
            var 等级 = 图像_.识别文字(398, 674, 516, 696).Trim();
            等级 = 等级.Replace("级", "");
            try
            {
                return int.Parse(等级);
            }
            catch
            {
                return 0;
            }
        }

        public static string 识别右姓名()
        {
            return 图像_.识别文字(813, 674, 956, 696).Trim(); ;
        }

        public static string 识别右职业()
        {
            return 图像_.识别文字(1015, 674, 1072, 696).Trim(); ;
        }

        public static int 识别右等级()
        {
            var 等级 = 图像_.识别文字(1127, 674, 1247, 696).Trim(); ;
            等级 = 等级.Replace("级", "");
            try
            {
                return int.Parse(等级);
            }
            catch
            {
                return 0;
            }
        }

        public static Point 弹出了确认窗口()
        {
            return 图像_.查找文字(600, 400, 700, 460, (string s) => s.Contains("确") || s.Contains("定"));
        }

        public static Point 找到联系我们()
        {
            return 图像_.查找文字("联系我们", 307, 236, 412, 265);
        }

        public static Point 找到关注公众号即可联系官服客服()
        {
            return 图像_.查找文字(625, 243, 900, 269, (string s) =>
            {
                return s.Contains("关注公众号");
            });
        }

        public static bool 查找游戏登陆公告(int 次数)
        {
            if (其他_.循环判断(() => 找到联系我们().X != -1, 次数))
            {
                键鼠_.左键单击(其他_.取中心(307, 236, 412, 265));
                其他_.延迟(其他_.时长_2000);
            }
            return  其他_.循环判断(()=>找到关注公众号即可联系官服客服().X != -1, 次数);
        }

        public static Point 查找游戏标签图标()
        {
            return 图像_.查找图片(Properties.Resources.游戏标签图标, 310, 11, 385, 30);
        }

        public static Point 查找996登录窗口()
        {
            return 图像_.查找文字(572, 207, 708, 232, (string s) =>
            {
                return s.Contains("996");
            });
        }

        public static Point 查找点击屏幕登录()
        {
            return 图像_.查找文字(510, 365, 764, 416, (string s) =>
            {
                return s.Contains("点击");
            });
        }

        public static Point 找到游戏图标()
        {
            var p = 图像_.查找图片(Properties.Resources.游戏图标, 140, 170, 600, 250);
            if (p.X != -1)
            {
                return new Point(p.X + Properties.Resources.游戏图标.Width / 2, p.Y + Properties.Resources.游戏图标.Height / 2);
            }
            return p;
        }

        public static Point 找到进入游戏按钮()
        {
            return 图像_.查找文字(591, 489, 688, 516, (string s) =>
            {
                return s.Contains("游戏");
            });
        }

        public static Point 找到确定登陆按钮()
        {
            var p = 图像_.查找文字(359, 718, 460, 737, (string s) =>
            {
                return s.Contains("删除");
            });

            if (p.X != -1)
            {
                return new Point(p.X + 280, p.Y);
            }
            return p;
        }

        public static bool 打开今日挑战()
        {
            if (今日挑战是关闭的())
            {
                键鼠_.左键单击(1027, 173);
                var 结果 = 今日挑战是打开的();
                if (!结果) throw new Exception("打开今日挑战失败");
            }
            return true;
        }

        public static bool 今日挑战是打开的()
        {
            return 其他_.循环判断(() => 图像_.查找文字("当天活跃", 234, 162, 312, 188).X != -1 && 图像_.查找文字("任务信息", 271, 266, 351, 288).X != -1, 4, 500);
        }

        public static bool 今日挑战是关闭的()
        {
            return 其他_.循环判断(() => 图像_.查找文字("当天活跃", 234, 162, 312, 188).X == -1 || 图像_.查找文字("任务信息", 271, 266, 351, 288).X == -1, 4, 500);
        }

        public static bool 判断地图名(string 名称, int 次数 = 20)
        {
            return 其他_.循环判断(() => 图像_.识别文字(地图名位置范围) == 名称, 次数);
        }

        public static bool 关闭今日挑战()
        {
            if (今日挑战是打开的())
            {
                键鼠_.左键单击(864, 95);
                var 结果 = 今日挑战是关闭的();
                if (!结果) throw new Exception("关闭今日挑战失败");
            }
            return true;
        }

        public static Point 找到游戏健康公告()
        {
            return 图像_.查找文字("健康游戏公告", 516, 436, 641, 460);
        }

        // 地图操作
        public static string 识别小地图当前地图名()
        {
            return 图像_.识别文字(296, 134, 435, 165).Trim();
        }

        public static bool 关闭小地图()
        {
            var 结果 = 小地图是打开的();
            if (!结果) return true;
            键鼠_.左键单击(1105, 94);
            结果 = 小地图是关闭的();
            if (!结果) throw new Exception("关闭小地图失败");
            return true;
        }

        public static bool 打开小地图()
        {
            var 结果 = 小地图是打开的();
            if (结果) return true;
            键鼠_.左键单击(1194, 137);
            结果 = 小地图是打开的();
            if (!结果) throw new Exception("打开小地图失败");
            return true;
        }

        public static bool 小地图是打开的()
        {
            return 其他_.循环判断(() => 图像_.查找文字("小地图", 602, 77, 674, 98).X != -1, 4, 500);
        }

        public static bool 小地图是关闭的()
        {
            return 其他_.循环判断(() => 图像_.查找文字("小地图", 602, 77, 674, 98).X == -1, 4, 500);
        }

        public static Rectangle 地图名位置范围 = Rectangle.FromLTRB(1121, 35, 1271, 54);
        public static Rectangle 角色坐标点范围 = Rectangle.FromLTRB(1187, 210, 1256, 226);
        public static Rectangle NPC名称范围 = Rectangle.FromLTRB(918, 421, 1015, 447);
        public static Rectangle 使用回城范围 = Rectangle.FromLTRB(997, 522, 1088, 551);

        public static Point 挂机按钮位置 = new Point(1181, 352);

        public static bool 开启内挂(bool 不报错 = false)
        {
            if (UI_.识别没开启内挂())
            {
                键鼠_.左键单击(挂机按钮位置);
                var 结果 = UI_.识别已开启内挂();
                if (!结果 && !不报错) throw new Exception("开启内挂失败");
            }
            return true;
        }

        public static bool 关闭内挂()
        {
            if (UI_.识别已开启内挂())
            {
                键鼠_.左键单击(挂机按钮位置);
                var 结果 = UI_.识别没开启内挂();
                if (!结果) throw new Exception("关闭内挂失败");
            }
            return true;
        }

        public static bool 你已阵亡()
        {
            return 图像_.查找文字("立即复活", 637, 433, 726, 458).X != -1;
        }

        public static bool 识别已开启内挂()
        {
            return !其他_.循环判断(() => 图像_.查找文字(Rectangle.FromLTRB(1146, 365, 1175, 381), s => s.Contains("自") || s.Contains("动")).X != -1, 4, 500);
        }

        public static bool 识别没开启内挂()
        {
            return !其他_.循环判断(() => 图像_.查找文字(Rectangle.FromLTRB(1146, 365, 1175, 381), s => s.Contains("自") || s.Contains("动")).X == -1, 4, 500);
        }

        public static bool 材料行没收缩()
        {
            return 其他_.循环判断(() =>
            {
                return 图像_.查找文字(901, 89, 962, 114, (string s) => s.Contains("材料行")).X != -1
                || 图像_.查找文字(894, 184, 975, 207, (string s) => s.Contains("竞技")).X != -1;
            }, 10, 500);
        }

        public static bool 材料行已收缩()
        {
            return 其他_.循环判断(() =>
            {
                return 图像_.查找文字(901, 89, 962, 114, (string s) => s.Contains("材料行")).X == -1
                || 图像_.查找文字(894, 184, 975, 207, (string s) => s.Contains("竞技")).X == -1;
            }, 10, 500);
        }

        public static bool 设置展开材料行()
        {
            if (材料行已收缩())
            {
                键鼠_.左键单击(1088, 52);
                var 没收缩 = 材料行没收缩();
                if (!没收缩) throw new Exception("未能正确展开材料行");
            }
            return true;
        }

        public static Point 人物坐标基点 = new Point(640, 400);
        public static Point 坐标比例值 = new Point(66, 33);

        public static Point 计算屏幕坐标点位(坐标_ 当前, 坐标_ 目标, out 移动方向_ 方向)
        {
            方向 = 判断移动方向(当前, 目标);
            var Y = Math.Abs(目标.Y - 当前.Y);
            var X = Math.Abs(目标.X - 当前.X);
            switch (方向)
            {
                case 移动方向_.上_:
                    {
                        return new Point(人物坐标基点.X, 人物坐标基点.Y - Y * 坐标比例值.Y);
                    }
                case 移动方向_.下_:
                    {
                        return new Point(人物坐标基点.X, 人物坐标基点.Y - Y * 坐标比例值.Y);
                    }
                case 移动方向_.左_:
                    {
                        return new Point(人物坐标基点.X - X * 坐标比例值.X, 人物坐标基点.Y);
                    }
                case 移动方向_.右_:
                    {
                        return new Point(人物坐标基点.X + X * 坐标比例值.X, 人物坐标基点.Y);
                    }
                case 移动方向_.左上_:
                    {
                        return new Point(人物坐标基点.X - X * 坐标比例值.X, 人物坐标基点.Y - Y * 坐标比例值.Y);
                    }
                case 移动方向_.右上_:
                    {
                        return new Point(人物坐标基点.X + X * 坐标比例值.X, 人物坐标基点.Y - Y * 坐标比例值.Y);
                    }
                case 移动方向_.左下_:
                    {
                        return new Point(人物坐标基点.X - X * 坐标比例值.X, 人物坐标基点.Y + Y * 坐标比例值.Y);
                    }
                case 移动方向_.右下_:
                    {
                        return new Point(人物坐标基点.X + X * 坐标比例值.X, 人物坐标基点.Y + Y * 坐标比例值.Y);
                    }
            }
            return new Point(人物坐标基点.X, 人物坐标基点.Y);
        }
        public static bool 设置收缩材料行()
        {
            var 没收缩 = 材料行没收缩();
            if (!没收缩) return true;
            键鼠_.左键单击(1088, 52);
            没收缩 = 材料行已收缩();
            if (!没收缩) throw new Exception("未能正确收缩材料行");
            return true;
        }

        public static bool 鼠标点击屏幕坐标(int X, int Y, 判断_ 是否成功, int 次数 = 5)
        {
            return 鼠标点击屏幕坐标(new 坐标_(X, Y), 是否成功, 次数);
        }

        public static bool 鼠标点击屏幕坐标(坐标_ 坐标, 判断_ 是否成功, int 次数 = 5)
        {
            var 成功 = 其他_.循环判断(是否成功, 1);
            if (成功) return true;
            var 重来次数 = 0;
        重来_:
            var 当前 = UI_.连续识别坐标();
            var p = UI_.计算屏幕坐标点位(当前, 坐标, out var 方向);
            if (其他_.点在有效范围内(p))
            {
                if (玩家怪物列表_.怪物列表范围.Contains(p) && 玩家怪物列表_.怪物列表已打开())
                {
                    玩家怪物列表_.关闭怪物列表();
                    其他_.延迟(200);
                    键鼠_.左键单击(p);
                    其他_.延迟(200);
                    玩家怪物列表_.打开怪物列表();
                }
                else
                {
                    键鼠_.左键单击(p);
                }
            }
            else
            {
                重来次数++;
                UI_.移动(方向, 100);
                其他_.延迟(其他_.时长_600);
                if (重来次数 < 5) goto 重来_;
            }
            成功 = 其他_.循环判断(是否成功, 次数);
            if (!成功)
            {
                重来次数++;
                if (UI_.今日挑战是打开的())
                {
                    UI_.关闭今日挑战();
                    goto 重来_;
                }
                if (UI_.小地图是打开的())
                {
                    UI_.关闭小地图();
                    goto 重来_;
                }
                if (!UI_.画面在一秒钟内是变化的())
                {
                    throw new Exception("游戏宕机, 重启模拟器");
                }
                UI_.移动(方向, 100);
                其他_.延迟(其他_.时长_600);
                if (重来次数 < 5) goto 重来_;
            }
            if (!成功) throw new Exception("点击屏幕坐标失败");
            return 成功;
        }

        public static 地图_ 获取当前地图(int 识别次数 = 5)
        {
            var 地图名 = "";
            var 有地图 = 其他_.循环判断(() =>
            {
                地图名 = 识别地图名();
                return 地图集_.有地图(地图名);
            }, 识别次数);
            if (有地图)
            {
                return 地图集_.获取地图(地图名);
            }
            throw new Exception("未能识别地图");
        }

        public static string 识别地图名()
        {
            if (小地图是打开的())
            {
                return 识别小地图当前地图名();
            }
            return 图像_.识别文字(地图名位置范围);
        }

        public static bool 点击当前NPC名称(判断_ 验证)
        {
            键鼠_.左键单击(其他_.取中心(NPC名称范围));
            var 成功 = 其他_.循环判断(验证, 5);
            if (!成功) throw new Exception("点击NPC名称失败");
            return true;
        }

        public static bool 坐标点距离较近(Point 坐标a, Point 坐标b, int 比较)
        {
            return 坐标点距离较近(坐标a, 坐标b, 比较, 比较);
        }

        public static bool 坐标点距离较近(Point 坐标a, Point 坐标b, int 比较x, int 比较y)
        {
            var x = Math.Abs(坐标a.X - 坐标b.X);
            var y = Math.Abs(坐标a.Y - 坐标b.Y);
            return x <= 比较x && y <= 比较y;
        }

        public static bool 坐标点距离较近(坐标_ 坐标a, 坐标_ 坐标b, int 比较)
        {
            return 坐标点距离较近(坐标a, 坐标b, 比较, 比较);
        }

        public static bool 坐标点距离较近(坐标_ 坐标a, 坐标_ 坐标b, int 比较x, int 比较y)
        {
            var x = Math.Abs(坐标a.X - 坐标b.X);
            var y = Math.Abs(坐标a.Y - 坐标b.Y);
            return x <= 比较x && y <= 比较y;
        }

        public static 坐标_ 连续识别坐标(int 次数 = 1)
        {
            坐标_ 结果 = 识别坐标();
            if (次数 == 1 || 结果.X != -1) return 结果;
            UI_.关闭小地图();
            var i = 0;
            do
            {
                i++;
                结果 = 识别坐标();
                if (结果.X != -1) return 结果;
                其他_.打印("随机动一下重识别坐标. ");
                UI_.移动((移动方向_)其他_.随机数(8), 100);
            }
            while (i < 次数);
            return 结果;
        }

        public static 坐标_ 识别坐标()
        {
            try
            {
                var text = 图像_.识别文字(角色坐标点范围);
                var xy = text.Split(new char[] { ',', '.' });
                var x = Convert.ToInt32(xy[0].Trim(), 10);
                var y = Convert.ToInt32(xy[1].Trim(), 10);
                return new 坐标_(x, y);
            }
            catch
            {
                return new 坐标_(-1, -1);
            }
        }

        public static bool 通过雷达地图判断角色是否在移动()
        {
            return 图像_.屏幕找色("B8FF00", 1121, 71, 1262, 202, 0.95).X != -1;
        }

        public static bool 使用回城()
        {
            打开小地图();
            var 存在 = 图像_.查找文字("使用回城", 使用回城范围);
            if (存在.X != -1)
            {
                键鼠_.左键单击(1044, 537);
                其他_.延迟(其他_.时长_1000);
            }
            关闭小地图();

            var 到达 = UI_.判断地图名("跃马大平原");
            到达 = 到达 && 画面在一秒钟内是变化的(5000);
            if (!到达) throw new Exception("回城失败");
            return 到达;
        }

        public static void 使用随机(挂机人物_ 人物)
        {
            if (人物.随机次数 <= 0)
            {
                商城_.购买第一页物品(人物, new List<物品及数量_> { new 物品及数量_("随机神石", 1) });
            }
            打开小地图();
            点击使用随机按钮(人物);
            关闭小地图();
        }

        public static void 点击使用随机按钮(挂机人物_ 人物)
        {
            人物.随机次数--;
            键鼠_.左键单击(1041, 424);
            其他_.延迟(其他_.时长_200);
        }

        public static void 使用快捷回城石(挂机人物_ 人物)
        {
            if (人物.包裹.快捷回城石位.X != -1)
            {
                var 识别随机位 = 人物.包裹.是什么物品(人物.包裹.快捷回城石位, 0.6);
                if (识别随机位 == _物品_.回城石_)
                {
                    键鼠_.左键单击(人物.包裹.快捷回城石位);
                    人物.输出("使用快捷回城石");
                    var 到达 = UI_.判断地图名("跃马大平原", 5);
                    if (到达) return;
                }
            }
            UI_.使用回城();
        }

        public static void 使用快捷随机(挂机人物_ 人物)
        {
            if (人物.包裹.快捷随机位.X == -1)
            {
                人物.包裹.识别快捷栏内物品();
            }
            var 购买次数 = 0;
        在来一次_:
            if (人物.包裹.快捷随机位.X != -1)
            {
                var 识别随机位 = 人物.包裹.是什么物品(人物.包裹.快捷随机位, 0.6);
                if (识别随机位 == _物品_.随机神石_)
                {
                    键鼠_.左键单击(人物.包裹.快捷随机位);
                    人物.输出("使用快捷随机神石");
                    其他_.延迟(其他_.时长_1000);
                    return;
                }
            }
            购买次数++;
            if (购买次数 == 1)
            {
                人物.包裹.在包内找到随机神石移动到快捷栏();
                goto 在来一次_;
            }
            人物.输出("快捷栏没有随机神石");
        }

        public static bool 已经接了军机任务(out int 任务)
        {
            其他_.延迟(其他_.时长_3000);
            var 内容 = 图像_.识别文字(45, 30, 145, 60);
            任务 = -1;
            if (内容.Contains("军机"))
            {
                内容 = 图像_.识别文字(45, 60, 145, 90);
                if (内容.Contains("前往"))
                {
                    任务 = 判断是军机任务几(内容);
                }
                return true;
            }
            内容 = 图像_.识别文字(45, 120, 145, 150);
            if (内容.Contains("军机"))
            {
                内容 = 图像_.识别文字(45, 150, 145, 180);
                if (内容.Contains("前往"))
                {
                    任务 = 判断是军机任务几(内容);
                }
                return true;
            }
            内容 = 图像_.识别文字(45, 150, 145, 180);
            if (内容.Contains("军机"))
            {
                内容 = 图像_.识别文字(45, 180, 145, 210);
                if (内容.Contains("前往"))
                {
                    任务 = 判断是军机任务几(内容);
                }
                return true;
            }

            return false;

            int 判断是军机任务几(string 地图信息)
            {
                if (地图信息.Contains("将"))
                {
                    return 0;
                }
                if (地图信息.Contains("机"))
                {
                    return 1;
                }
                if (地图信息.Contains("蛇"))
                {
                    return 2;
                }
                if (地图信息.Contains("逆"))
                {
                    return 3;
                }
                if (地图信息.Contains("禁"))
                {
                    return 4;
                }
                if (地图信息.Contains("通"))
                {
                    return 5;
                }
                if (地图信息.Contains("地"))
                {
                    return 6;
                }
                return -1;
            }

        }

        public static int 判断是否需要使用随机(坐标_ 当前坐标, 坐标_[] 目的坐标组, int 地图规模)
        {
            if (地图规模 == -1) return 0;
            for (var i = 0; i < 目的坐标组.Length; i++)
            {
                var 目的坐标 = 目的坐标组[i];

                var 结果 = Math.Abs(当前坐标.X - 目的坐标.X) >= 地图规模 || Math.Abs(当前坐标.Y - 目的坐标.Y) >= 地图规模;
                if (!结果) return i;
            }
            return -1;
        }

        public static bool 判断是否需要使用随机(坐标_ 当前坐标, 坐标_ 目的坐标, int 地图规模)
        {
            if (地图规模 == -1) return false;
            return Math.Abs(当前坐标.X - 目的坐标.X) >= 地图规模 || Math.Abs(当前坐标.Y - 目的坐标.Y) >= 地图规模;
        }

        public static bool 切换到跑路()
        {
            if (是走步())
            {
                键鼠_.左键单击(1256, 725);
            }
            return 其他_.循环判断(是跑步, 5, 500);
        }

        public static bool 切换到走路()
        {
            if (是跑步())
            {
                键鼠_.左键单击(1256, 725);
            }
            return 其他_.循环判断(是走步, 5, 500);
        }

        public static bool 是走步()
        {
            return 图像_.查找文字("走", Rectangle.FromLTRB(1217, 731, 1239, 749)).X != -1;
        }

        public static bool 是跑步()
        {
            return 图像_.查找文字("跑", Rectangle.FromLTRB(1217, 731, 1239, 749)).X != -1;
        }

        public delegate bool 判断位置();
        public delegate void 处理问题();

        public static bool 根据地图比例移动到大概位置(挂机人物_ 人物, 地图_ 地图, 坐标_ 坐标)
        {
            var p = 地图.获取对应点(坐标);
            if (p.X == -1) return false;
            return 移动到地图内大概位置(人物, 地图, p, 坐标);
        }

        public static void 点击捡物()
        {
            键鼠_.左键单击(960, 507);
        }

        public static void 关注雷达地图等待角色移动(int 时长 = 1000)
        {
            while (通过雷达地图判断角色是否在移动())
            {
                其他_.延迟(时长);
            }
            while (true)
            {
                var 坐标 = UI_.识别坐标();
                其他_.延迟(时长 / 2);
                var 坐标2 = UI_.识别坐标();
                if (坐标 == 坐标2) break;
                其他_.延迟(时长 / 2);
            }
            其他_.延迟(时长 / 2);
        }

        public static Point 在像素点附近随机选择新像素点(Point 像素点)
        {
            return new Point(其他_.随机加或减去指定数(像素点.X, 1), 其他_.随机加或减去指定数(像素点.Y, 1));
        }
        public static bool 移动到地图内准确位置(Point 像素点)
        {
            if (打开小地图())
            {
                键鼠_.左键单击(像素点);
            }
            return 关闭小地图();
        }

        public static int 移动到地图内大概位置(挂机人物_ 人物, 点及坐标_[] 位置)
        {
            var 当前坐标 = 连续识别坐标();
            if (当前坐标.Y == -1)
            {
                return -1;
            }
            var 地图 = UI_.获取当前地图();
            var 地图规模 = 地图.获取随机接受范围值();
            var 需要使用随机 = 判断是否需要使用随机(当前坐标, 位置.Select((点及坐标_ a) => a.坐标).ToArray(), 地图规模);
            if (需要使用随机 == -1)
            {
                return 随机到合格点(地图, 人物, 位置.Select((点及坐标_ a) => a.像素点).ToArray(), 地图规模);
            }
            else
            {
                if (打开小地图())
                {
                    键鼠_.左键单击(位置[需要使用随机].像素点);
                    其他_.延迟(其他_.时长_1000);
                }
                关闭小地图();
                return 需要使用随机;
            }
        }

        public static bool 移动到地图内大概位置(挂机人物_ 人物, 地图_ 地图, Point XY, 坐标_ 位置)
        {
            if ((地图.属性 & 地图属性_.不可随机_) == 0)
            {
                var 当前坐标 = 连续识别坐标();
                if (当前坐标.Y == -1) 变化位置随机移动();
                var 地图规模 = 地图.获取随机接受范围值();
                var 需要使用随机 = 判断是否需要使用随机(当前坐标, 位置, 地图规模);
                if (需要使用随机) return 随机到合格点(地图, 人物, XY, 地图规模);
            }

            return 变化位置随机移动();

            bool 变化位置随机移动()
            {
                UI_.打开小地图();
                var xy = XY;
                do
                {
                    键鼠_.左键单击(xy);
                    if (判断角色是否在移动())
                    {
                        break;
                    }
                    xy = 在像素点附近随机选择新像素点(XY);
                }
                while (true);
                其他_.延迟(其他_.时长_1000);
                return 关闭小地图();
            }
        }

        public static bool 判断角色是否在移动()
        {
            if (UI_.小地图是打开的())
            {
                var 屏幕有路径 = 图像_.屏幕找多点色("B8FF00", 170, 165, 929, 679).Count > 4;
                if (屏幕有路径) return true;
                var a = 图像_.屏幕在一段时间内的变化点(Rectangle.FromLTRB(175, 180, 930, 691), 1000);
                var b = 图像_.屏幕在一段时间内的变化点(Rectangle.FromLTRB(175, 180, 930, 691), 1000);
                return Math.Abs(a.X - b.X) > 2 || Math.Abs(a.Y - b.Y) > 2;
            }
            else
            {
                var 屏幕有路径 = 通过雷达地图判断角色是否在移动();
                if (屏幕有路径) return true;
                var a = UI_.识别坐标();
                其他_.延迟(其他_.时长_400);
                var b = UI_.识别坐标();
                return a.X != b.X || a.Y != b.Y;
            }
        }

        public static int 检查小地图内移动路径长度()
        {
            return 图像_.屏幕找多点色("B8FF00", 170, 165, 929, 679).Count / 4;
        }

        public static int 随机到合格点(地图_ 当前地图, 挂机人物_ 人物, Point[] 点位组, int 合格范围 = 50, int 最多随机次数 = 20)
        {
            if (点位组.Length == 1)
            {
                var 到达 = 随机到合格点(当前地图, 人物, 点位组[0], 合格范围, 最多随机次数);
                if (到达) return 0;
                return -1;
            }
            int i = 0, 上一次数量 = -1, 当前点数量, 连续次数 = 0;
            打开小地图();
        开始_:
            var 索引 = 0;
            var 点位 = 点位组[索引];
            键鼠_.左键单击(点位.X, 点位.Y);
            其他_.延迟(其他_.时长_2000);
            合格范围 += 5 * i;
            i++;
            点击使用随机按钮(人物);
            其他_.延迟(其他_.时长_2000);
            if (i >= 最多随机次数)
            {
                关闭小地图();
                return -1;
            }
        重随_:
            当前点数量 = 检查小地图内移动路径长度();
            if (上一次数量 == -1)
            {
                上一次数量 = 当前点数量;
            }
            else
            {
                var 数值差 = Math.Abs(上一次数量 - 当前点数量);
                if (数值差 < 15)
                {
                    连续次数++;
                    if (连续次数 >= 3)
                    {
                        关闭小地图();
                        return -1;
                    }
                }
                else
                {
                    连续次数 = 0;
                }
            }
        重新算零_:
            if (当前点数量 > 合格范围)
            {
                索引++;
                if (索引 < 点位组.Length)
                {
                    键鼠_.左键单击(点位组[索引].X, 点位组[索引].Y);
                    其他_.延迟(其他_.时长_2000);
                    goto 重随_;
                }
                goto 开始_;
            }
            else if (当前点数量 == 0)
            {
                var 当前像素位置 = UI_.角色在小地图中位置();
                if (当前像素位置.X != -1)
                {
                    if (坐标点距离较近(当前像素位置, 点位组[索引], 5))
                    {
                        当前点数量 = 合格范围 - 1;
                        goto 重新算零_;
                    }
                }
                当前点数量 = 合格范围 + 1;
                goto 重新算零_;
            }
            else
            {
                关闭小地图();
                return 索引;
            }
        }
        public static bool 随机到合格点(地图_ 当前地图, 挂机人物_ 人物, Point 点位, int 合格范围 = 50, int 最多随机次数 = 20)
        {
            int i = 0, 上一次数量 = -1, 当前点数量, 连续次数 = 0;
            打开小地图();
            键鼠_.左键单击(点位.X, 点位.Y);
            其他_.延迟(其他_.时长_2000);
            if ((当前地图.属性 & 地图属性_.不可随机_) != 0)
            {
                return 关闭小地图();
            }
            do
            {
                合格范围 += 5 * i;
                i++;
                点击使用随机按钮(人物);
                其他_.延迟(其他_.时长_2000);
                if (i >= 最多随机次数) return false;
                当前点数量 = 检查小地图内移动路径长度();
                if (上一次数量 == -1)
                {
                    上一次数量 = 当前点数量;
                }
                else
                {
                    var 数值差 = Math.Abs(上一次数量 - 当前点数量);
                    if (数值差 < 15)
                    {
                        连续次数++;
                        if (连续次数 >= 3)
                        {
                            return 关闭小地图();
                        }
                    }
                    else
                    {
                        连续次数 = 0;
                    }
                }
                if (当前点数量 == 0)
                {
                    var 当前像素位置 = UI_.角色在小地图中位置();
                    if (当前像素位置.X != -1)
                    {
                        if (坐标点距离较近(当前像素位置, 点位, 5))
                        {
                            当前点数量 = 合格范围 - 1;
                        }
                    }
                }
            }
            while (当前点数量 == 0 || 当前点数量 > 合格范围);

            return 关闭小地图();
        }

        public static bool 画面在一秒钟内是变化的(int 时长 = 1000)
        {
            return 图像_.屏幕在一段时间内的变化点(Rectangle.FromLTRB(626, 234, 656, 266), 时长 + 100).X != -1;
        }

        public static Point 角色在小地图中位置(bool 关闭 = false)
        {
            if (打开小地图())
            {
                var 结果 = 图像_.屏幕在一段时间内的变化点(Rectangle.FromLTRB(175, 180, 930, 691), 1200);
                if (关闭)
                {
                    关闭小地图();
                }
                return 结果.X != -1 ? new Point(结果.X + 4, 结果.Y + 4) : 结果;
            }
            return new Point(-1, -1);
        }

        public enum 移动方向_
        {
            无_,
            左_,
            左上_,
            上_,
            右上_,
            右_,
            右下_,
            下_,
            左下_
        }

        public static 移动方向_ 判断移动方向(坐标_ 角色位置, 坐标_ 目标位置)
        {
            var X = 角色位置.X - 目标位置.X;
            var Y = 角色位置.Y - 目标位置.Y;
            if (X == 0)
            {
                if (Y == 0)
                {
                    return 移动方向_.无_;
                }
                else if (Y > 0)
                {
                    return 移动方向_.上_;
                }
                else
                {
                    return 移动方向_.下_;
                }
            }
            else if (X > 0)
            {
                if (Y == 0)
                {
                    return 移动方向_.左_;
                }
                else if (Y > 0)
                {
                    return 移动方向_.左上_;
                }
                else
                {
                    return 移动方向_.左下_;
                }
            }
            else
            {
                if (Y == 0)
                {
                    return 移动方向_.右_;
                }
                else if (Y > 0)
                {
                    return 移动方向_.右上_;
                }
                else
                {
                    return 移动方向_.右下_;
                }
            }
        }
        public static 移动方向_ 根据位置判断方向(坐标_ 角色位置, 坐标_ 目标位置, out int 时长, bool 是跑 = true)
        {
            var X = 角色位置.X - 目标位置.X;
            var Y = 角色位置.Y - 目标位置.Y;
            var x = Math.Abs(X);
            var y = Math.Abs(Y);
            var 基数 = x > 5 || y > 5 ? 是跑 ? 200 : 600 : 200;
            if (X == 0)
            {
                if (Y == 0)
                {
                    时长 = 0;
                    return 移动方向_.无_;
                }
                else if (Y > 0)
                {
                    时长 = Math.Min(y * 基数, 10000);
                    return 移动方向_.上_;
                }
                else
                {
                    时长 = Math.Min(y * 基数, 10000);
                    return 移动方向_.下_;
                }
            }
            else if (X > 0)
            {
                if (Y == 0)
                {
                    时长 = Math.Min(x * 基数, 10000);
                    return 移动方向_.左_;
                }
                else if (Y > 0)
                {
                    时长 = Math.Min(Math.Max(x, y) * 基数, 10000);
                    return 移动方向_.左上_;
                }
                else
                {
                    时长 = Math.Min(Math.Max(x, y) * 基数, 10000);
                    return 移动方向_.左下_;
                }
            }
            else
            {
                if (Y == 0)
                {
                    时长 = Math.Min(x * 基数, 10000);
                    return 移动方向_.右_;
                }
                else if (Y > 0)
                {
                    时长 = Math.Min(Math.Max(x, y) * 基数, 10000);
                    return 移动方向_.右上_;
                }
                else
                {
                    时长 = Math.Min(Math.Max(x, y) * 基数, 10000);
                    return 移动方向_.右下_;
                }
            }
        }
        public static void 移动(移动方向_ 方向, int 时长)
        {
            switch (方向)
            {
                case 移动方向_.左_:
                    内部移动(时长, 169 - 25, 574);
                    break;
                case 移动方向_.左上_:
                    内部移动(时长, 169 - 19, 574 - 19);
                    break;
                case 移动方向_.上_:
                    内部移动(时长, 169, 574 - 25);
                    break;
                case 移动方向_.右上_:
                    内部移动(时长, 169 + 19, 574 - 19);
                    break;
                case 移动方向_.右_:
                    内部移动(时长, 169 + 25, 574);
                    break;
                case 移动方向_.右下_:
                    内部移动(时长, 169 + 19, 574 + 19);
                    break;
                case 移动方向_.下_:
                    内部移动(时长, 169, 574 + 25);
                    break;
                case 移动方向_.左下_:
                    内部移动(时长, 169 - 19, 574 + 19);
                    break;
                case 移动方向_.无_:
                    break;
            }

            void 内部移动(int 长, int x, int y)
            {
                键鼠_.移动鼠标(x, y);
                键鼠_.左键按下();
                其他_.延迟(长);
                键鼠_.左键抬起();
            }
        }
    }
}
